package com.redhat.auth.log.parse;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import com.redhat.auth.log.annotation.LogBizCall;
import com.redhat.auth.log.annotation.DataValue;
import com.redhat.auth.log.annotation.LogBizExecution;
import com.redhat.auth.log.annotation.QueryKeyValue;
import com.redhat.auth.log.annotation.RecordValue;
import com.redhat.auth.log.annotation.ValueType;
import com.redhat.auth.log.common.LogDescriptionBean;
import com.redhat.auth.log.common.QueryValueBean;
import com.redhat.auth.log.common.RecordValueBean;
import com.redhat.auth.log.common.ValueBean;

/**
 * 解析Annotation定义，产生一个LogDescriptionBean对象
 * 
 * @author lingen.liu
 * 
 */
public class AnnotationParse {

	/**
	 * 将anntation定义的业务规则解析成为LogDescriptionBean对象，以便后面程序使用到
	 * 
	 * @param logBizDescription
	 * @return
	 */
	public static LogDescriptionBean parseAnnotation(
			LogBizCall logBizDescription) {
		if (logBizDescription == null)
			throw new RuntimeException("can't find LogBizDescription");
		LogDescriptionBean logBean = new LogDescriptionBean();
		logBean.setHandlerClass(logBizDescription.handlerClass());
		logBean.setFailureException(logBizDescription.failureException());
		logBean.setAuthorType(logBizDescription.operator().authorType());
		logBean.setSpecialAuthor(logBizDescription.operator().authorName());
		logBean.setBizDescription(logBizDescription.bizDescription());
		logBean.setBizOperationType(logBizDescription.bizOperationType());
		DataValue[] values = logBizDescription.dataValue();
		
		
		RecordValue[] recordValues  = logBizDescription.recordValue();
		List<RecordValueBean> RecordValueBeanList =new ArrayList<RecordValueBean>();
		for(RecordValue recordValue:recordValues){
			RecordValueBean recordValueBean = new RecordValueBean();
			recordValueBean.setKey(recordValue.key());
			recordValueBean.setValueType(recordValue.valueType());
			recordValueBean.setExpr(recordValue.expr());
			RecordValueBeanList.add(recordValueBean);
		}
		logBean.setRecordValues(RecordValueBeanList);
		
		HashMap<Class, ValueBean> valueList = new LinkedHashMap<Class, ValueBean>();
		for (DataValue value : values) {
			ValueBean valueBean = new ValueBean();
			valueBean.setOperaType(value.operaType());
			valueBean.setEntity(value.entity());
			QueryKeyValue[] queryKeyValues = value.queryKeyValues();
			List<QueryValueBean> queryKeyValueBeanList = new ArrayList<QueryValueBean>();
			for(QueryKeyValue queryKeyValue:queryKeyValues){
				queryKeyValueBeanList.add(new QueryValueBean(queryKeyValue.key(),queryKeyValue.queryValueType(),queryKeyValue.expr()));
			}
			valueBean.setQueryKeyValues(queryKeyValueBeanList);
			List<String> cascadeList = CascadeParse.initValueBeanCascade(value.entity(), RecordValueBeanList);
			valueBean.setCascadeProperties(cascadeList);
			valueList.put(value.entity(), valueBean);
		}
		logBean.setValues(valueList);
		return logBean;
	}
	

	public static LogDescriptionBean parseAnnotationExecution(
			LogBizExecution logBizDescription) {
		if (logBizDescription == null)
			throw new RuntimeException("can't find LogBizDescription");
		LogDescriptionBean logBean = new LogDescriptionBean();
		logBean.setHandlerClass(logBizDescription.handlerClass());
		logBean.setFailureException(logBizDescription.failureException());
		logBean.setAuthorType(logBizDescription.operator().authorType());
		logBean.setSpecialAuthor(logBizDescription.operator().authorName());
		logBean.setBizDescription(logBizDescription.bizDescription());
		logBean.setBizOperationType(logBizDescription.bizOperationType());
		DataValue[] values = logBizDescription.dataValue();
		
		
		RecordValue[] recordValues  = logBizDescription.recordValue();
		List<RecordValueBean> RecordValueBeanList =new ArrayList<RecordValueBean>();
		for(RecordValue recordValue:recordValues){
			RecordValueBean recordValueBean = new RecordValueBean();
			recordValueBean.setKey(recordValue.key());
			recordValueBean.setValueType(recordValue.valueType());
			recordValueBean.setExpr(recordValue.expr());
			RecordValueBeanList.add(recordValueBean);
		}
		logBean.setRecordValues(RecordValueBeanList);
		
		HashMap<Class, ValueBean> valueList = new LinkedHashMap<Class, ValueBean>();
		for (DataValue value : values) {
			ValueBean valueBean = new ValueBean();
			valueBean.setOperaType(value.operaType());
			valueBean.setEntity(value.entity());
			QueryKeyValue[] queryKeyValues = value.queryKeyValues();
			List<QueryValueBean> queryKeyValueBeanList = new ArrayList<QueryValueBean>();
			for(QueryKeyValue queryKeyValue:queryKeyValues){
				queryKeyValueBeanList.add(new QueryValueBean(queryKeyValue.key(),queryKeyValue.queryValueType(),queryKeyValue.expr()));
			}
			valueBean.setQueryKeyValues(queryKeyValueBeanList);
			List<String> cascadeList = CascadeParse.initValueBeanCascade(value.entity(), RecordValueBeanList);
			valueBean.setCascadeProperties(cascadeList);
			valueList.put(value.entity(), valueBean);
		}
		logBean.setValues(valueList);
		return logBean;
	}

	/**
	 * 返回一个对象的所有的属性值，关联属性除外
	 * 
	 * @param obj
	 * @return
	 */
	public static String[] getAllProperties(Class objC) {
		List<String> filedList = new ArrayList<String>();
		Field[] fields = objC.getDeclaredFields();
		for (Field field : fields) {
			if(field.getAnnotation(Column.class)!=null || field.getAnnotation(Id.class)!=null)
			filedList.add(field.getName());
			if(field.getAnnotation(EmbeddedId.class)!=null){
				filedList.addAll(getEmbeddedId(field.getName(),field.getType()));
			}
		}
		String[] properties = new String[filedList.size()];
		for (int i = 0; i < filedList.size(); i++) {
			properties[i] = filedList.get(i);
		}
		return properties;
	}

	/**
	 * 返回一个对象的所有的属性值，指定排除某些属性
	 * 
	 * @param obj
	 * @return
	 */
	public static String[] getAllProperties(Class objC, String[] excludes) {
		List<String> filedList = new ArrayList<String>();
		List<String> excludeList = Arrays.asList(excludes);
		Field[] fields = objC.getDeclaredFields();
		for (Field field : fields) {
			if(excludeList.contains(field.getName()))continue;
			if(field.getAnnotation(Column.class)!=null || field.getAnnotation(Id.class)!=null)
			filedList.add(field.getName());
			if(field.getAnnotation(EmbeddedId.class)!=null){
				filedList.addAll(getEmbeddedId(field.getName(),field.getType()));
			}
		}
		String[] properties = new String[filedList.size()];
		for (int i = 0; i < filedList.size(); i++) {
			properties[i] = filedList.get(i);
		}
		return properties;
	}
	
	private static List<String> getEmbeddedId(String name,Class objC){
		List<String> filedList = new ArrayList<String>();
		Field[] fields = objC.getDeclaredFields();
		for (Field field : fields) {
			if(field.getAnnotation(Column.class)!=null && field.getAnnotation(Id.class)!=null)
			filedList.add(name+"."+field.getName());
		}
		return filedList;
	}
}
